package com.ygp.lock.rlock.threadsinal;

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <Description> <br>
 *
 * @author linmiaolai@sanyygp.com<br>
 * @version 1.0<br>
 * @date 2021/11/18 <br>
 */
@Slf4j(topic = "c.boundedContainer")
public class BoundedContainer {

    final Lock lock = new ReentrantLock();
    /**
     * 不能空的条件
     */
    final Condition notFull = lock.newCondition();
    /**
     * 不能满的条件
     */
    final Condition notEmpty = lock.newCondition();


    private int count;

    private int putIndex;

    private int takeIndex;

    private Object[] items;

    private int cap;

    public BoundedContainer(int initialCapacity) {
        this.cap = initialCapacity;
        this.count = 0;
        this.items = new Object[initialCapacity];
        this.putIndex = 0;
        this.takeIndex = 0;
    }


    public void put(Object item) throws InterruptedException {
        lock.lock();
        try {
            while (count == cap) {
                System.out.println(String.format("put方法：满了,无法添加 %s,进入等待", item));
                notFull.await();
            }
            if (putIndex == cap) {
                // 要重头开始
                putIndex = 0;
            }
            items[putIndex++] = item;
            count++;
            System.out.println("put方法：" + Arrays.toString(items));
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                System.out.println("task方法：没有元素,进入等待");
                notEmpty.await();
            }
            if (takeIndex == cap) {
                takeIndex = 0;
            }
            Object item = items[takeIndex];
            items[takeIndex] = null;
            takeIndex++;
            count--;
            System.out.println("take方法：" + Arrays.toString(items));
            notFull.signal();
            return item;
        } finally {
            lock.unlock();
        }
    }

    public void print() {
        System.out.println(Arrays.toString(items));
    }
}
